#pragma once
#include "net.hpp"
#include "message.hpp"

namespace MyRpc
{
	class MessageCB
	{
	public:
		using ptr = std::shared_ptr<MessageCB>;
		virtual void OnMessageCB(const BaseConnection::ptr &, const BaseMessage::ptr &) = 0;
	private:
	};

	template<class T>
	class MessageCBT : public MessageCB
	{
	// 把这个MessageCallBack函数封装成一个类
	public:
		using ptr = std::shared_ptr<MessageCBT<T>>;
		// 是对回调函数中第二个参数进行类处理
		using MeCalBac = std::function<void(const BaseConnection::ptr &, const std::shared_ptr<T> &msg)>;
		MessageCBT(const MeCalBac& handler)
			:_handler(handler)
		{}
		virtual void OnMessageCB(const BaseConnection::ptr &conn, const BaseMessage::ptr &msg) override
		{
			// 把回调函数的参数转化为他本身进行调用 而不是基类进行调用
			auto type_cb = std::dynamic_pointer_cast<T>(msg);
			_handler(conn, type_cb);
		}
	private:
		MeCalBac _handler;
	};

	class Dispatcher
	{
	public:
        using ptr = std::shared_ptr<Dispatcher>;
		// 把这个回调处理的函数设置为模板类
		template<class T>
		void Register(const MType &mtype, const typename MessageCBT<T>::MeCalBac &onmessage)
		{
			std::lock_guard<std::mutex> lockguard(_mtx);
			// 构建一个回调函数对象的类 把传过来的回调函数传进去
			MessageCB::ptr type_cb = std::make_shared<MessageCBT<T>>(onmessage);
			_mcb.insert(std::make_pair(mtype, type_cb));
		}
		// 要对这个MessageCallBack的第二个参数进行用类模板来实现
		void OnMessage(const BaseConnection::ptr &conn, const BaseMessage::ptr &msg)
		{
			std::lock_guard<std::mutex> lockguard(_mtx);
			auto it = _mcb.find(msg->mtype());
			if (it == _mcb.end())
			{
				// 没有找到这个函数调用
				// 关闭连接
				LOG(DEBUGLEVEL, "没有找到这个函数调用!");
				conn->shutdown();
			}
			// 这里就是找到了 直接调用 这里调用的时候进行了转换为它本身的对象进行调用
			it->second->OnMessageCB(conn, msg);
		}

	private:
		std::mutex _mtx;
		std::unordered_map<MType, MessageCB::ptr> _mcb;
	};
	std::shared_ptr<Dispatcher> disp = std::make_shared<Dispatcher>();
}
